package com.topisv.tms.service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springside.modules.persistence.DynamicSpecifications;
import org.springside.modules.persistence.SearchFilter;
import org.springside.modules.persistence.SearchFilter.Operator;

import com.topisv.tms.entity.LogisticsMailNo;
import com.topisv.tms.repository.LogisticsMailNoDao;

//Spring Bean的标识.
@Component
// 默认将类中的所有public函数纳入事务管理.
@Transactional(readOnly = true)
public class LogisticsMailNoService {
    private static final Logger logger = LoggerFactory.getLogger(LogisticsMailNo.class);
	
	@Autowired
	private LogisticsMailNoDao logisticsMailNoDao;
	@PersistenceContext
    private EntityManager em;
	
	@Transactional(readOnly = false)
	public List<String> save(List<String> mailNos,String areaGroupCode,String companyCode,String sequence)throws Exception{
		try {
			Date createTime=new Date();
			for(String mail:mailNos){
				LogisticsMailNo lm=new LogisticsMailNo();
				lm.setAreaGroupCode(areaGroupCode);
				lm.setCompanyCode(companyCode);
				lm.setCreateTime(createTime);
				lm.setMailNo(mail);
				lm.setSequence(sequence);
				lm.setStatus("pending");
				logisticsMailNoDao.save(lm);
			}
			return mailNos;
		} catch (Exception e) {
			throw e;
		}
	}
	@Transactional(readOnly = false)
	public LogisticsMailNo save(LogisticsMailNo arg0){
		return logisticsMailNoDao.save(arg0);
	}
	@Transactional(readOnly = false)
	public List<LogisticsMailNo> save(List<LogisticsMailNo> arg0){
		return (List<LogisticsMailNo>) logisticsMailNoDao.save(arg0);
	}
	
	/**
	 * 查询电子面单号
	 * @param status 状态 未使用(pending),使用了(finish)
	 * @param companyCode 快递公司编码
	 * @param areaGroupCode 网点编码
	 * @param pageSize 查询多少
	 * @return
	 */
	public List<LogisticsMailNo> getLogisticsMailNo(String status, String companyCode,String areaGroupCode, int pageSize) {
		PageRequest pageRequest = buildPageRequest(1, pageSize);
		Specification<LogisticsMailNo> spec = buildSpecification(status, companyCode,areaGroupCode);
		return logisticsMailNoDao.findAll(spec,pageRequest).getContent();
	}
	
	
	/**
	 * 获取未使用过的运单号
	 *
	 * @param companyCode 快递公司编码
	 * @param areaGroupCode 仓库编码
	 * @return 获取到的面单号
	 * @author <a href=mailto:yuanlianghe@nryuncang.com>yuanlianghe</a>
	 * @version 1.0.0
	 */
	@Transactional(readOnly=false, propagation=Propagation.REQUIRES_NEW)
	public String getLogisticsMailNo(String orderNo, String companyCode, String areaGroupCode) {
	    String mailNo = findLogisticsMailNo(orderNo, companyCode, areaGroupCode);
	    if (mailNo != null && mailNo.length() > 0) {
	        return mailNo;
	    }
	    
	    String sql = "UPDATE logistics_mail_no SET status=?, order_no=?, version=version+? WHERE status=? AND company_code=? and area_group_code=? limit ?";
	    Query query = em.createNativeQuery(sql);
	    
	    int i = 1;
	    query.setParameter(i++, "finish");
	    query.setParameter(i++, orderNo);
	    query.setParameter(i++, 1);
	    query.setParameter(i++, "pending");
	    query.setParameter(i++, companyCode);
	    query.setParameter(i++, areaGroupCode);
	    query.setParameter(i++, 1);
	    
	    int cnt = query.executeUpdate();
	    if (cnt == 0) {
	        logger.error("单号:[{}], 快递公司:[{}], 仓库:[{}] 获取面单号失败,无可用面单号.", orderNo, companyCode, areaGroupCode);
	        throw new RuntimeException("单号:[" + orderNo + "], 快递公司:[" + companyCode + "], 仓库:[" + areaGroupCode + "] 获取面单号失败,无可用面单号.");
	    }
	    
	    mailNo = findLogisticsMailNo(orderNo, companyCode, areaGroupCode);
	    if (mailNo == null || mailNo.length() == 0) {
	        logger.error("单号:[{}], 快递公司:[{}], 仓库:[{}] 锁定面单号后再获取面单号为空.", orderNo, companyCode, areaGroupCode);
	        throw new RuntimeException("单号:[" + orderNo + "], 快递公司:[" + companyCode + "], 仓库:[" + areaGroupCode + "] 锁定面单号后再获取面单号为空.");
	    }
	    
	    return mailNo;
	}
	
	public String findLogisticsMailNo(String orderNo, String companyCode, String areaGroupCode) {
	    String sql = "SELECT mail_no FROM logistics_mail_no WHERE order_no=? AND company_code=? AND area_group_code=? AND status=? limit ?";
	    Query query = em.createNativeQuery(sql);
        
        int i = 1;
        query.setParameter(i++, orderNo);
        query.setParameter(i++, companyCode);
        query.setParameter(i++, areaGroupCode);
        query.setParameter(i++, "finish");
        query.setParameter(i++, 1);
        
        try {
            return  (String) query.getSingleResult();
        } catch (NoResultException ex) {
            
            sql = "UPDATE logistics_mail_no SET order_no=?, status=? WHERE order_no=? AND area_group_code=?";
            query = em.createNativeQuery(sql);
            i = 1;
            query.setParameter(i++, "-");
            query.setParameter(i++, "pending");
            query.setParameter(i++, orderNo);
            query.setParameter(i++, areaGroupCode);
            query.executeUpdate();
            
	    } catch (Exception ex) {
            throw ex;
        }
        
        return null;
	}

	/**
	 * 创建分页请求.
	 */
	private PageRequest buildPageRequest(int pageNumber, int pagzSize) {
		return new PageRequest(pageNumber - 1, pagzSize, null);
	}

	/**
	 * 创建动态查询条件组合.
	 */
	private Specification<LogisticsMailNo> buildSpecification(String status, String companyCode,String areaGroupCode) {
		Map<String, SearchFilter> filters = new HashMap<String, SearchFilter>();
		filters.put("status", new SearchFilter("status", Operator.EQ, status));
		filters.put("companyCode", new SearchFilter("companyCode", Operator.EQ, companyCode));
		filters.put("areaGroupCode", new SearchFilter("areaGroupCode", Operator.EQ, areaGroupCode));
		Specification<LogisticsMailNo> spec = DynamicSpecifications.bySearchFilter(filters.values(), LogisticsMailNo.class);
		return spec;
	}

}
